package com.pickgliss.local.uygur
{
	import com.pickgliss.utils.ArrayUtils;
	import com.pickgliss.utils.StringUtils;
	
	import flash.utils.Dictionary;
	import flash.utils.getTimer;

	public final class UygurRverter
	{
		private static var BPAD:int = 0x0600; // Basic region
		private static var BMAX:int = 0x06FF;
		private static var EPAD:int = 0xFB00; // presentation form region (extented region)
		private static var EMAX:int = 0xFEFF;
		
		private static var CHEE:int  = 0x0686;
		private static var GHEE:int  = 0x063A;
		private static var NGEE:int  = 0x06AD;
		private static var SHEE:int  = 0x0634;
		private static var SZEE:int  = 0x0698;
		
		private static var LA:int  = 0xFEFB;
		private static var _LA:int  = 0xFEFC;
		private static var HAMZA:int = 0x0626;
		
		private static var needInit:Boolean = true;
		public static function getReverString(text:String):String
		{
			init();
			var revall:String = "";
			var lines:Array = text.split("\n");
			for(var j:int = 0;j<lines.length;j++)
			{
				var str:String = getUyPFStr(lines[j]);
				if ( str.charAt(str.length-1) == '\r' ) // get rid of last CR
				{
					str = str.substring(0, str.length-1);
				}
				var tstr:String = "";
				var rev:String = "";
				var isalpha:Boolean = false;
				var worlds:Array = StringUtils.trim(str).split(' ');
				var newWords:Array = [];
				for(var k:int = 0;k<worlds.length;k++)
				{
					var word:String = worlds[k];
					var newWord:String = "";
					for(var m:int = 0;m<word.length;m++)
					{
						var char:int = word.charCodeAt(m);
						if(charIsAlpha(char))
						{
							newWord += String.fromCharCode(char);
						}else
						{
							newWord = String.fromCharCode(char) + newWord;
						}
					}
					newWords.push(newWord);
				}
				if ( j != 0 ) 
				{
					revall += "\r\n";
				}
				var result:Array = arrangeWords(newWords);
				revall += result.join(" ");;
			}
			return revall;
		}
		
		public static function getHtmlReverString(text:String):String
		{
			init();
			var revall:String = "";
			var lines:Array = text.split("<BR>");
			for(var j:int = 0;j<lines.length;j++)
			{
				var str:String = getUyPFStr(lines[j]);
				if ( str.charAt(str.length-1) == '\r' ) // get rid of last CR
				{
					str = str.substring(0, str.length-1);
				}
				var tstr:String = "";
				var rev:String = "";
				var isalpha:Boolean = false;
				var words:Array = splitHtmlTag(str);
				var newWords:Array = [];
				for(var k:int = 0;k<words.length;k++)
				{
					var word:String = words[k];
					var newWord:String = "";
					for(var m:int = 0;m<word.length;m++)
					{
						var char:int = word.charCodeAt(m);
						if(charIsAlpha(char))
						{
							newWord += String.fromCharCode(char);
						}else
						{
							newWord = String.fromCharCode(char) + newWord;
						}
					}
					newWords.push(newWord);
				}
				if ( j != 0 ) 
				{
					revall += "<BR>";
				}
				var result:Array = arrangeHtmlWords(newWords);
				revall += result.join("");
			}
			return revall;
		}
		
		private static function arrangeHtmlWords(words:Array):Array
		{
			var tags:Array = [];
			for(var i:int = 0;i<words.length;i++)
			{
				if(isHtmlTag(words[i]))
				{
					tags.push(words[i]);
				}
			}
			
			var rightWords:Array = arrangeWords(words);
			for(var k:int = 0;k<tags.length;k++)
			{
				if(!StringUtils.beginsWith(tags[k],"</"))
				{
					var endTagIndex:int = findEndTagIndex(tags,tags[k],k);
					if( endTagIndex < 0) continue;
					ArrayUtils.swapItems(rightWords,tags[k],tags[endTagIndex]);
				}
			}
			return rightWords;
		}
		
		private static function findEndTagIndex(tags:Array,begin:String,startIndex:int):int
		{
			for(var i:int = startIndex;i<tags.length;i++)
			{
				if(begin.toLocaleLowerCase() == "<br>")return -1;
				if(tagIsMatch(begin,tags[i]))return i;
			}
			return -1;
		}
		
		private static function tagIsMatch(begin:String,endtag:String):Boolean
		{
			if(begin == endtag)return false;
			var startName:String = begin.substring(1,begin.indexOf(" "));
			var endName:String = endtag.substr(2,endtag.length -3);
			endName = StringUtils.trim(endName);
			return startName == endName;
		}
		
		public static function splitHtmlTag(line:String):Array
		{
			var result:Array = [];
			for(var i:int = 0;i<line.length;i++)
			{
				if(line.charAt(i) == "<")
				{
					result.push(line.substring(i,line.indexOf(">",i)+1));
					i = line.indexOf(">",i);
					continue;
				}else
				{
					var nextopenB:int = line.indexOf("<",i);
					var nextBlank:int = line.indexOf(" ",i);
					if(nextopenB == -1)nextopenB = 0xFFFFFF;
					if(nextBlank == -1)nextBlank = 0xFFFFFF;
					
					if(nextopenB < nextBlank)
					{
						result.push(line.substring(i,nextopenB));
						i = nextopenB - 1;
					}else if(nextBlank < nextopenB)
					{
						result.push(line.substring(i,nextBlank+1));
						i = nextBlank;
					}else
					{
						result.push(line.substring(i,line.length-1));
						i = line.length;
					}
				}
			}
			return result;
		}
			
		private static function arrangeWords(newWords:Array):Array
		{
			var resultWords:Array = [];
			var rangeWords:Array = [];
			var lastRangeIndex:int = 0;
			for(var n:int = 0;n<newWords.length;n++)
			{
				var tempWords:Array;
				if(n == 0)
				{
					tempWords = [];
					tempWords.push(newWords[n])
					rangeWords.push(tempWords);
					continue;
				}
				if(isUygur(newWords[n]))
				{
					tempWords = [];
					tempWords.push(newWords[n]);
					rangeWords.unshift(tempWords);
				}else
				{
					if(isUygur(newWords[n - 1]))
					{
						tempWords = [];
						tempWords.push(newWords[n]);
						rangeWords.unshift(tempWords);
						lastRangeIndex = rangeWords.indexOf(tempWords);
					}else
					{
						rangeWords[lastRangeIndex].push(newWords[n]);
					}
				}
			}
			
			for(var i:int = 0;i<rangeWords.length;i++)
			{
				resultWords = resultWords.concat(rangeWords[i]);
			}
			
			return resultWords;
		}
		
		private static function isUygur(word:String):Boolean
		{
			for(var i:int = 0;i<word.length;i++)
			{
				var char:int =word.charCodeAt(i);
				if(char >= EPAD && char <= EMAX)return true;
			}
			return false;
		}
		
		private static function isHtmlTag(words:String):Boolean
		{
			return StringUtils.beginsWith(words,"<") && StringUtils.endsWith(words,">");
		}
		
		private static var cmap:Dictionary = new Dictionary();
		private static var pform:Dictionary = new Dictionary();
		private static function init():void
		{
			if(!needInit)return;
			needInit = false;
			cmap['A'] = 0x0627 ;
			cmap['a'] = 0x0627 ;
			cmap['B'] = 0x0628 ;
			cmap['b'] = 0x0628 ;
			cmap['C'] = 0x0643 ;
			cmap['c'] = 0x0643 ;
			cmap['D'] = 0x062F ;
			cmap['d'] = 0x062F ;
			cmap['E'] = 0x06D5 ;
			cmap['e'] = 0x06D5 ;
			cmap['F'] = 0x0641 ;
			cmap['f'] = 0x0641 ;
			cmap['G'] = 0x06AF ;
			cmap['g'] = 0x06AF ;
			cmap['H'] = 0x06BE ;
			cmap['h'] = 0x06BE ;
			cmap['I'] = 0x0649 ;
			cmap['i'] = 0x0649 ;
			cmap['J'] = 0x062C ;
			cmap['j'] = 0x062C ;
			cmap['K'] = 0x0643 ;
			cmap['k'] = 0x0643 ;
			cmap['L'] = 0x0644;
			cmap['l'] = 0x0644 ;
			cmap['M'] = 0x0645 ;
			cmap['m'] = 0x0645 ;
			cmap['N'] = 0x0646 ;
			cmap['n'] = 0x0646 ;
			cmap['O'] = 0x0648 ;
			cmap['o'] = 0x0648 ;
			cmap['P'] = 0x067E ;
			cmap['p'] = 0x067E;
			cmap['Q'] = 0x0642 ;
			cmap['q'] = 0x0642 ;
			cmap['R'] = 0x0631 ;
			cmap['r'] = 0x0631 ;
			cmap['S'] = 0x0633 ;
			cmap['s'] = 0x0633 ;
			cmap['T'] = 0x062A;
			cmap['t'] = 0x062A;
			cmap['U'] = 0x06C7;
			cmap['u'] = 0x06C7;
			cmap['V'] = 0x06CB;
			cmap['v'] = 0x06CB ;
			cmap['W'] = 0x06CB ;
			cmap['w'] = 0x06CB ;
			cmap['X'] = 0x062E ;
			cmap['x'] = 0x062E ;
			cmap['Y'] = 0x064A ;
			cmap['y'] = 0x064A ;
			cmap['Z'] = 0x0632 ;
			cmap['z'] = 0x0632 ;
			
			cmap['É']  = 0x06D0 ;
			cmap['é']  = 0x06D0; 
			cmap['Ö' ] = 0x06C6 ;
			cmap['ö']  = 0x06C6 ; 
			cmap['Ü']  = 0x06C8 ;
			cmap['ü']  = 0x06C8;
			
			// Uyghur punctuation marks
			cmap [ ';' ] = 0x061B ;
			cmap [ '?' ] = 0x061F ;
			cmap [ ',' ] = 0x060C ;
			
			
			
			pform[ cmap['a'] - BPAD ]    = new Ligatures ( 0xFE8D, 0xFE8D, 0xFE8D, 0xFE8E, BegType.WDBEG ) ;
			pform[ cmap['e'] - BPAD ]    = new Ligatures ( 0xFEE9, 0xFEE9, 0xFEE9, 0xFEEA, BegType.WDBEG ) ;
			pform[ cmap['b'] - BPAD ]    = new Ligatures ( 0xFE8F, 0xFE91, 0xFE92, 0xFE90, BegType.NOBEG ) ;
			pform[ cmap['p'] - BPAD ]    = new Ligatures ( 0xFB56, 0xFB58, 0xFB59, 0xFB57, BegType.NOBEG ) ;
			pform[ cmap['t'] - BPAD ]    = new Ligatures ( 0xFE95, 0xFE97, 0xFE98, 0xFE96, BegType.NOBEG ) ;
			pform[ cmap['j'] - BPAD ]    = new Ligatures ( 0xFE9D, 0xFE9F, 0xFEA0, 0xFE9E, BegType.NOBEG ) ;
			pform[ CHEE-BPAD ]  = new Ligatures ( 0xFB7A, 0xFB7C, 0xFB7D, 0xFB7B, BegType.NOBEG ) ;
			pform[ cmap['x'] - BPAD ]    = new Ligatures ( 0xFEA5, 0xFEA7, 0xFEA8, 0xFEA6, BegType.NOBEG ) ;
			pform[ cmap['d'] - BPAD ]    = new Ligatures ( 0xFEA9, 0xFEA9, 0xFEAA, 0xFEAA, BegType.INBEG ) ;
			pform[ cmap['r'] - BPAD ]    = new Ligatures ( 0xFEAD, 0xFEAD, 0xFEAE, 0xFEAE, BegType.INBEG ) ;
			pform[ cmap['z'] - BPAD ]    = new Ligatures ( 0xFEAF, 0xFEAF, 0xFEB0, 0xFEB0, BegType.INBEG ) ;
			pform[ SZEE-BPAD ]  = new Ligatures ( 0xFB8A, 0xFB8A, 0xFB8B, 0xFB8B, BegType.INBEG ) ;
			pform[ cmap['s'] - BPAD ]    = new Ligatures ( 0xFEB1, 0xFEB3, 0xFEB4, 0xFEB2, BegType.NOBEG ) ;
			pform[ SHEE-BPAD ]  = new Ligatures ( 0xFEB5, 0xFEB7, 0xFEB8, 0xFEB6, BegType.NOBEG ) ;
			pform[ GHEE-BPAD ]  = new Ligatures ( 0xFECD, 0xFECF, 0xFED0, 0xFECE, BegType.NOBEG ) ;
			pform[ cmap['f'] - BPAD ]    = new Ligatures ( 0xFED1, 0xFED3, 0xFED4, 0xFED2, BegType.NOBEG ) ;
			pform[ cmap['q'] - BPAD ]    = new Ligatures ( 0xFED5, 0xFED7, 0xFED8, 0xFED6, BegType.NOBEG ) ;
			pform[ cmap['k'] - BPAD ]    = new Ligatures ( 0xFED9, 0xFEDB, 0xFEDC, 0xFEDA, BegType.NOBEG ) ;
			pform[ cmap['g'] - BPAD ]    = new Ligatures ( 0xFB92, 0xFB94, 0xFB95, 0xFB93, BegType.NOBEG ) ;
			pform[ NGEE-BPAD ]  = new Ligatures ( 0xFBD3, 0xFBD5, 0xFBD6, 0xFBD4, BegType.NOBEG ) ;
			pform[ cmap['l'] - BPAD ]    = new Ligatures ( 0xFEDD, 0xFEDF, 0xFEE0, 0xFEDE, BegType.NOBEG ) ;
			pform[ cmap['m'] - BPAD ]    = new Ligatures ( 0xFEE1, 0xFEE3, 0xFEE4, 0xFEE2, BegType.NOBEG ) ;
			pform[ cmap['n'] - BPAD ]    = new Ligatures ( 0xFEE5, 0xFEE7, 0xFEE8, 0xFEE6, BegType.NOBEG ) ;
			pform[ cmap['h'] - BPAD ]    = new Ligatures ( 0xFEEB, 0xFEEB, 0xFEEC, 0xFEEC, BegType.NOBEG ) ;
			pform[ cmap['o'] - BPAD ]    = new Ligatures ( 0xFEED, 0xFEED, 0xFEEE, 0xFEEE, BegType.INBEG ) ;
			pform[ cmap['u'] - BPAD ]    = new Ligatures ( 0xFBD7, 0xFBD7, 0xFBD8, 0xFBD8, BegType.INBEG ) ;
			pform[ cmap['ö'] - BPAD ]   = new Ligatures ( 0xFBD9, 0xFBD9, 0xFBDA, 0xFBDA, BegType.INBEG ) ;
			pform[ cmap['ü'] - BPAD ]   = new Ligatures ( 0xFBDB, 0xFBDB, 0xFBDC, 0xFBDC, BegType.INBEG ) ;
			pform[ cmap['w'] - BPAD ]    = new Ligatures ( 0xFBDE, 0xFBDE, 0xFBDF, 0xFBDF, BegType.INBEG ) ;
			pform[ cmap['é'] - BPAD ]  = new Ligatures ( 0xFBE4, 0xFBE6, 0xFBE7, 0xFBE5, BegType.NOBEG ) ;
			pform[ cmap['i'] - BPAD ]    = new Ligatures ( 0xFEEF, 0xFBE8, 0xFBE9, 0xFEF0, BegType.NOBEG ) ;
			pform[ cmap['y'] - BPAD ]    = new Ligatures ( 0xFEF1, 0xFEF3, 0xFEF4, 0xFEF2, BegType.NOBEG ) ;
			pform[ HAMZA-BPAD ] = new Ligatures ( 0xFE8B, 0xFE8B, 0xFE8C, 0xFB8C, BegType.NOBEG ) ;
		}
		
		private static function charIsAlpha(ch:int):Boolean
		{
			if ( ( 'A'.charCodeAt() <= ch && ch <= 'Z'.charCodeAt() ) || ('a'.charCodeAt() <= ch && ch <= 'z'.charCodeAt()) ) 
			{
				return true ;
			}
			if(( '0'.charCodeAt() <= ch && ch <= '9'.charCodeAt() ) )
			{
				return true;
			}
			if(ch == '<'.charCodeAt())return true;
			if(ch == '>'.charCodeAt())return true;
			if(ch == '['.charCodeAt())return true;
			if(ch == ']'.charCodeAt())return true;
			if(ch == '\''.charCodeAt())return true;
			if(ch == '/'.charCodeAt())return true;
			if(ch == '='.charCodeAt())return true;
			if(ch == '\"'.charCodeAt())return true;
			if(ch == '#'.charCodeAt())return true;
			if(ch == '!'.charCodeAt())return true;
			if(ch == '%'.charCodeAt())return true;
			if(ch == '.'.charCodeAt())return true;
			if(ch == '。'.charCodeAt())return true;
			if(ch == ' '.charCodeAt())return true;
			return false ;
		}
		
		private static function getUyPFStr(str:String):String
		{
			var lsyn:Ligatures = pform[ cmap['l'] - BPAD ] ;
			var syn:Ligatures;
			var tsyn:Ligatures;
			var bt:int = BegType.WDBEG;
			
			var wp:String = str;
			var pfstr:String = "";
			var n:int = str.length;
			var i:int = 0;
			var j:int = 0;
			
			var wc:int; 
			var pfwc:int = 0;
			var prevwc:int = 0;
			var ppfwc:int = 0; 
			
			var pfwp:Vector.<int> = new Vector.<int>(n);
			var numberWords:Array = [];
			var lastNumberWordIndex:int;
			for ( i = 0 ; i < n ; i++ ) 
			{
				wc  = wp.charCodeAt(i);
				if (BPAD <= wc && wc < BMAX) 
				{
					syn = pform [ wc - BPAD ] ;
					if ( syn != null ) 
					{
						switch ( bt ) 
						{
							case BegType.WDBEG:
								pfwc = syn.iform ;
								break ;
							case BegType.INBEG:
								pfwc = syn.iform ;
								break ;
							case BegType.NOBEG:
								pfwc = syn.eform ;
								break ;
							default:
								break ;
						}
						
						
						if ( bt != BegType.WDBEG ) 
						{ 
							tsyn = pform [ prevwc - BPAD ] ;
							
							// special cases for LA and _LA
							if ( ppfwc == lsyn.iform && wc == cmap['a'] ) 
							{
								pfwp[j-1] = LA ;
								bt = BegType.WDBEG ;
								continue ;
							} 
							else if ( ppfwc == lsyn.eform && wc == cmap['a'] ) 
							{
								pfwp[j-1] = _LA ;
								bt = BegType.WDBEG ;
								continue ;
							}
							
							// update previous character
							if ( ppfwc == tsyn.iform ) 
							{
								pfwp[j-1] = tsyn.bform ;
							} 
							else if ( ppfwc == tsyn.eform ) 
							{
								pfwp[j-1] = tsyn.mform ;
							}
						}
						bt = syn.btype ; // we will need this in next round
					} 
					else 
					{ // a non-Uyghur char in basic range
						pfwc = wc ;
						bt = BegType.WDBEG ;
					}
				}
				else 
				{ // not in basic Arabic range ( 0x0600-0x06FF )
					pfwc = wc ;
					bt = BegType.WDBEG ;
				}
				pfwp[j] = pfwc ;
				ppfwc   = pfwc ; // previous presentation form wide character
				prevwc  = wc ;
				j++ ;
			}
			
			for(var k:int = 0;k<j;k++)
			{
				pfstr += String.fromCharCode(pfwp[k]);
			}
			return pfstr ;
			
		}
		
		private static function isNumber(char:int):Boolean
		{
			return char>=48 && char<=57;
		}
	}
}